/*
 * @(#)PortMap.java	1.0 Mar 8, 2008
 *
 *	The MIT License
 *
 *	Copyright (c) 2008 Malachi de AElfweald <malachid@gmail.com>
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *	THE SOFTWARE.
 */
package org.eoti.net;

import static org.eoti.net.PortConfiguration.Protocol;

import java.util.LinkedHashMap;
import java.util.concurrent.locks.ReentrantLock;

public class PortMap
{
	public enum WellKnownPort
	{
		echo(Protocol.tcp, 7),
		echo2(Protocol.udp, 7),
		discard(Protocol.tcp, 9),
		discard2(Protocol.udp, 9),
		systat(Protocol.tcp, 11),
		systat2(Protocol.udp, 11),
		daytime(Protocol.tcp, 13),
		daytime2(Protocol.udp, 13),
		qotd(Protocol.tcp, 17),
		qotd2(Protocol.udp, 17),
		chargen(Protocol.tcp, 19),
		chargen2(Protocol.udp, 19),
		ftpdata(Protocol.tcp, 20),
		ftp(Protocol.tcp, 21),
		telnet(Protocol.tcp, 23),
		smtp(Protocol.tcp, 25),
		time(Protocol.tcp, 37),
		time2(Protocol.udp, 37),
		rlp(Protocol.udp, 39),
		nameserver(Protocol.tcp, 42),
		nameserver2(Protocol.udp, 42),
		nicname(Protocol.tcp, 43),
		domain(Protocol.udp, 53),
		domain2(Protocol.tcp, 53),
		bootps(Protocol.udp, 67),
		bootpc(Protocol.udp, 68),
		tftp(Protocol.udp, 69),
		gopher(Protocol.tcp, 70),
		finger(Protocol.tcp, 79),
		http(Protocol.tcp, 80),
		kerberos(Protocol.tcp, 88),
		kerberos2(Protocol.udp, 88),
		hostname(Protocol.tcp, 101),
		isotsap(Protocol.tcp, 102),
		rtelnet(Protocol.tcp, 107),
		pop2(Protocol.tcp, 109),
		pop3(Protocol.tcp, 110),
		sunrpc(Protocol.tcp, 111),
		sunrpc2(Protocol.udp, 111),
		auth(Protocol.tcp, 113),
		uucppath(Protocol.tcp, 117),
		nntp(Protocol.tcp, 119),
		ntp(Protocol.udp, 123),
		epmap(Protocol.tcp, 135),
		epmap2(Protocol.udp, 135),
        netbiosns(Protocol.tcp, 137),
        netbiosns2(Protocol.udp, 137),
        netbiosdgm(Protocol.udp, 138),
        netbiosssn(Protocol.tcp, 139),
        imap(Protocol.tcp, 143),
        pcmailsrv(Protocol.tcp, 158),
        snmp(Protocol.udp, 161),
        snmptrap(Protocol.udp, 162),
        printsrv(Protocol.tcp, 170),
        bgp(Protocol.tcp, 179),
        irc(Protocol.tcp, 194),
        ipx(Protocol.udp, 213),
        ldap(Protocol.tcp, 389),
        https(Protocol.tcp, 443),
        https2(Protocol.tcp, 443),
        microsoftds(Protocol.tcp, 445),
        microsoftds2(Protocol.udp, 445),
        kpasswd(Protocol.tcp, 464),
        kpasswd2(Protocol.udp, 464),
        isakmp(Protocol.udp, 500),
        exec(Protocol.tcp, 512),
        biff(Protocol.udp, 512),
        login(Protocol.tcp, 513),
        who(Protocol.udp, 513),
        cmd(Protocol.tcp, 514),
        syslog(Protocol.udp, 514),
        printer(Protocol.tcp, 515),
        talk(Protocol.udp, 517),
        ntalk(Protocol.udp, 518),
        efs(Protocol.tcp, 520),
        router(Protocol.udp, 520),
        timed(Protocol.udp, 525),
        tempo(Protocol.tcp, 526),
        courier(Protocol.tcp, 530),
        conference(Protocol.tcp, 531),
        netnews(Protocol.tcp, 532),
        netwall(Protocol.udp, 533),
        uucp(Protocol.tcp, 540),
        klogin(Protocol.tcp, 543),
        kshell(Protocol.tcp, 544),
        newrwho(Protocol.udp, 550),
        remotefs(Protocol.tcp, 556),
        rmonitor(Protocol.udp, 560),
        monitor(Protocol.udp, 561),
        ldaps(Protocol.tcp, 636),
        doom(Protocol.tcp, 666),
        doom2(Protocol.udp, 666),
        kerberosadm(Protocol.tcp, 749),
        kerberosadm2(Protocol.udp, 749),
        kerberosiv(Protocol.udp, 750),
        kpop(Protocol.tcp, 1109),
        phone(Protocol.udp, 1167),
        mssqls(Protocol.tcp, 1433),
        mssqls2(Protocol.udp, 1433),
        mssqlm(Protocol.tcp, 1434),
        mssqlm2(Protocol.udp, 1434),
        wins(Protocol.tcp, 1512),
        wins2(Protocol.udp, 1512),
        ingreslock(Protocol.tcp, 1524),
        l2tp(Protocol.udp, 1701),
        pptp(Protocol.tcp, 1723),
        radius(Protocol.udp, 1812),
        radacct(Protocol.udp, 1813),
        nfsd(Protocol.udp, 2049),
        knetd(Protocol.tcp, 2053),
        http2(Protocol.tcp, 8080),
        man(Protocol.tcp, 9535),
        attunityudaserver(Protocol.tcp, 2551),
        attunityudaserver2(Protocol.udp, 2551)
        ;

		WellKnownPort(PortConfiguration.Protocol proto, int port)
		{
			this.config = new PortConfiguration(proto,port);
		}
		protected PortConfiguration config;
		public PortConfiguration getConfig(){return config;}
	}

	protected LinkedHashMap<String,PortConfiguration> ports;
	protected PortMap()
	{
		ports = new LinkedHashMap<String,PortConfiguration>();
		for(WellKnownPort port : WellKnownPort.values())
			ports.put(port.toString(), port.getConfig());
	}

	private static ReentrantLock singletonLock = new ReentrantLock();
	private static PortMap singleton;

	public static PortMap getInstance(){
		// If singleton != null, then just return it (don't lock READ)
		if(singleton == null){
			// don't let more that one person create the singleton
			singletonLock.lock();

			// if we were waiting for a lock, then someone else already made it
			if(singleton == null)
				singleton = new PortMap();

			singletonLock.unlock();
		}

		return singleton;
	}

	public static void add(String name, PortConfiguration.Protocol proto, int port)
	{
		add(name, new PortConfiguration(proto, port));
	}

	public static void add(String name, PortConfiguration config)
	{
		getInstance().ports.put(name, config);
	}

	public static PortConfiguration get(String name)
	{
		return getInstance().ports.get(name);
	}
}
